In [37]:
#-*- coding: utf-8 -*-
  • 나이브베이즈로 들어가겠다. 텍스트 분석은 나이브 베이즈가 Good
  • 텍스트 분석이다 보니 텍스트 처리 기능을 알아야 한다.

Python 문자열 인코딩

문자와 인코딩

Python 2 문자열

  • string 타입 (기본)
    • 컴퓨터 환경에서 지정한 인코딩을 사용한 byte string
  • unicode 타입

    • 유니코드 코드 포인트(Unicode Code Point)를 사용한 내부 저장
    • string(byte string)과의 변환을 위해 encode(인코딩)/decode(디코딩) 명령 사용
  • Python 3에서는 unicode 타입이 기본

  • string <-> unicode point
  • 코드 포인트라는 개념을 알아야 한다.
  • 가장 좋은 점은 유니코드 포인트는 사이즈가 딱 정해져있다. 다른 글자들은 변한다.
  • 환경 설정에 따라서 실제로 “가나다”가 어떻게 컴퓨터 바이트에 들어가는지는 알 수가 없다. 그래서 설정을 봐야 한다.
  • 그러면 utf-8은 무엇인가? 유니코드 시스템이 나오기 전에 “가”를 “b7e9”로 변환하는 것이 인코딩 디코딩 개념이었다. 하지만 유니코드 시스템이 나온 이후로는 똑같은 “가”를 어떤 애는 “b7e9"나 ”a9b0"으로 표현한다. 인코딩과 상관없는 주민등록번호를 부여하자. “가”에다가. 그게 바로 유니코드 포인트를 말한다. 순수 int(eger)로 저장된다. 그런데 int 그대로 아까 본 인코딩된 것들과 맞출 수 없다. 예를 들어 KS, euc-kr, CP949등과 같은 기존의 방식들과 맞지가 않는다. 우리나라가 글자가 많고 빨리 신청해서 대다수의 유니코드 번호를 다 받아왔다. 그래서 int는 인코딩과 아무 상관없는 숫자다. C나 다른 랭귀지에는 유니코드 포인트라는 개념이 없다. 파이썬에서 u"~"하거나 .decode하면 유니코드로 변환해준다. utf-8은 이미 인코딩이 된 것이고 unicode point와 최대한 비슷하게 만든 것이다.

Python의 문자열 표시

  • __repr__()
    • 그냥 변수이름을 쳤을 때 나오는 표시
    • 다른 객체의 원소인 경우
    • 아스키 테이블로 표시할 수 없는 문자는 string 포맷으로 표시
  • print() 명령
    • 가능한 글리프(폰트)를 찾아서 출력

In [1]:
c = "a"
c


Out[1]:
'a'

In [2]:
print(c), type(c)


a <type 'str'>

In [3]:
#python2 기준. 인코딩 문제로 '가'가 아닌 특수문자들이 뜨는 경우가 있다. python3에서 실행할 경우에는 unicode로 되어 있기 때문에
#전부 정상적으로 한글 문자를 인식할 것이다.
x = "가"
x


Out[3]:
'\xea\xb0\x80'

In [4]:
print(x)



In [5]:
print(x.__repr__())


'\xea\xb0\x80'

In [8]:
x = ["가"]
print(x), type(x)


['\xea\xb0\x80'] <type 'list'>

In [9]:
x = "가"
len(x), type(x)


Out[9]:
(3, str)

In [10]:
x = "ABC"
y = "가나다"
print(len(x), len(y))
print(x[0], x[1], x[2])
print(y[0], y[1], y[2])
print(y[0], y[1], y[2], y[3])


(3, 9)
('A', 'B', 'C')
('\xea', '\xb0', '\x80')
('\xea', '\xb0', '\x80', '\xeb')

유니코드 리터럴(Literal)

  • 따옴표 앞에 u자를 붙이면 unicode 문자열로 인식
  • 내부적으로 유니코드 포인트로 저장

In [11]:
y = u"가"
y


Out[11]:
u'\uac00'

In [12]:
print(y)



In [18]:
y = u"가나다"
print(y[0])
print(y[1])
print(y[2])


가
나
다

In [19]:
y = u"가나다"
print(y[0], y[1], y[2])


(u'\uac00', u'\ub098', u'\ub2e4')

유니코드 인코딩(Encoding) / 디코딩(Decoding)

  • encode
    • unicode 타입의 메소드
    • unicode -> string (byte sequence)
  • decode
    • str 타입의 메소드
    • str -> unicode

In [20]:
print(type(y))
z1 = y.encode("cp949")
print(type(z1))
print(z1)


<type 'unicode'>
<type 'str'>
������

In [21]:
print(type(y))
z2 = y.encode("utf-8")
print(type(z2))
print(z2)


<type 'unicode'>
<type 'str'>
가나다

In [22]:
print(type(z1))
y1 = z1.decode("cp949")
print(type(y1))
print(y1)


<type 'str'>
<type 'unicode'>
가나다

In [23]:
print(type(z1))
y2 = z2.decode("utf-8")
print(type(y2))
print(y2)


<type 'str'>
<type 'unicode'>
가나다

str에 encode 메소드를 적용하면 또는 unicode에 decode 메소드를 적용하면?


In [24]:
"가".encode("utf-8")


---------------------------------------------------------------------------
UnicodeDecodeError                        Traceback (most recent call last)
<ipython-input-24-92305fa44153> in <module>()
----> 1 "가".encode("utf-8")

UnicodeDecodeError: 'ascii' codec can't decode byte 0xea in position 0: ordinal not in range(128)
  • 에러난 이유는 먼저 디코드를 하고 그 다음 인코드를 해야 하는데 그러지 못했음.
  • 아스키로 디코드를 하려는데 아스키에서 에러가 난 것임.

In [26]:
unicode("가", "ascii").encode("utf-8")


---------------------------------------------------------------------------
UnicodeDecodeError                        Traceback (most recent call last)
<ipython-input-26-c07f24263d81> in <module>()
----> 1 unicode("가", "ascii").encode("utf-8")

UnicodeDecodeError: 'ascii' codec can't decode byte 0xea in position 0: ordinal not in range(128)

In [37]:
u"가".decode("utf-8")



UnicodeEncodeErrorTraceback (most recent call last)
<ipython-input-37-e1c95bb5b4e2> in <module>()
----> 1 u"가".decode("utf-8")

/home/joel/anaconda2/lib/python2.7/encodings/utf_8.pyc in decode(input, errors)
     14 
     15 def decode(input, errors='strict'):
---> 16     return codecs.utf_8_decode(input, errors, True)
     17 
     18 class IncrementalEncoder(codecs.IncrementalEncoder):

UnicodeEncodeError: 'ascii' codec can't encode character u'\uac00' in position 0: ordinal not in range(128)
  • 이미 디코딩이 된 애. 유니코드 포인트.
  • 가라는 글자는 아스키로 인코딩 불가능 함. 에스키에 아예 없기 때문에

In [27]:
u"가".encode("ascii").decode("utf-8")


---------------------------------------------------------------------------
UnicodeEncodeError                        Traceback (most recent call last)
<ipython-input-27-99ffe5d7c928> in <module>()
----> 1 u"가".encode("ascii").decode("utf-8")

UnicodeEncodeError: 'ascii' codec can't encode character u'\uac00' in position 0: ordinal not in range(128)
  • str에 encode 메소드를 적용:
    • 내부적으로 유니코드로 변환 시도
  • unicode에 decode 메소드를 적용:
    • 바이트열이 스트링이라고 가정해 버린다.

디코드와 유니코드의 차이. 유니코드 포인트는 주민등록번호. 코드 포인트를 말함. 코드 포인트로 바꾸어 주는 것을 디코드라고 한다. 인코드는 그 반대

디폴트 인코딩


In [32]:
u"가".encode("utf-8"), u"가".encode("cp949"), "가"


Out[32]:
('\xea\xb0\x80', '\xb0\xa1', '\xea\xb0\x80')

In [33]:
u"가".encode("ascii")


---------------------------------------------------------------------------
UnicodeEncodeError                        Traceback (most recent call last)
<ipython-input-33-3640058d67fe> in <module>()
----> 1 u"가".encode("ascii")

UnicodeEncodeError: 'ascii' codec can't encode character u'\uac00' in position 0: ordinal not in range(128)

In [34]:
import sys
print(sys.getdefaultencoding())
print(sys.stdin.encoding)
print(sys.stdout.encoding)
import locale
print(locale.getpreferredencoding())


ascii
None
UTF-8
cp949

인코딩 설정

  • 콘솔(console) 입력의 경우
    • 지정하지 않을 경우 windows는 CP949, linux/mac은 LOCALE 설정에 따른다.
    • 환경변수 PYTHONIOENCODING 로 지정가능
  • 파일 입력의 경우
    • 첫줄에 다음과 같이 인코딩 설정
      #-*- coding: utf-8 -*-